package QianFeng04;

import java.awt.*;

/**
 * 继承：是从已有的类创建新类的过程
 * protected访问权限修饰符，在继承关系中使用，在父类中使用protected修饰的属性或方法可以被子类继承
 * 子类的实例化过程：
 * 1、创建子类对象时，父类的构造方法也会被调用（因为子类要使用到父类的数据，那么就要通过父类的构造方法来初始化数据）
 * 2、如果创建子类对象时会调用父类的默认构造方法
 * 3、实例化子类对象，会先调用父类的构造方法。如果父类中没有默认的构造方法（无参数构造方法），
 *      那么子类必须显示的通过super(...)来调用父类的带参构造方法，super也只能在子类构造方法中的第一句
 *
 * super关键字：
 * 1、使用super调用父类中的属性，可以从父类实例处获得信息。
 * 2、使用super调用父类中的方法，可以委托父类对象帮助完成某件事情。
 * 3、使用super调用父类中的构造方法(super(实参形式)， 必须在子类构造方法的第一条语句， 调用父类中相应的
 *      构造方法，若不显示的写出来，默认调用父类的无参构造方法，比如:super();
 * this表示当前对象，使用super来调用父类的属性、方法和构造方法
 *
 * 继承的限制：
 * 1、Java只能实现单继承，也就是一个类只能有一个父类
 * 2、允许多层继承，即:一个子类可以有一个父类，一个父类还可以有其他的父类。
 * 3、继承只能继承非私有的属性和方法。
 * 4、构造方法不能被继承
 * 继承的好处，
 * 1、提高代码的复用性
 * 2、提高代码的维护性
 * 3、让类与类之瓣产生关系，是多态的前提
 * 继承的缺点:
 * 1、增强了类与类之间的耦合性
 * 开发原则。高内聚，低耦合
 *
 *
 * 方法重写(overriding method)
 * 在Java中，子类可继承父类中的方法，而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方
 *      法，而是想做一定的修改，这就需要采用方法的重写。方法重写又称方法覆盖。
 * 在子类和父类中，重写方法后，在调用时，以创建的对象类型为准，会调用谁的方法。
 * 关于方法重写的一些特性:
 * 1、发生在子父类中，方法重写的两个方法返回值、方法名.参数列表必须完全一致(子类重写父类的方法)
 * 2、子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常)
 * 3、子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)
 *      如：父类方法使用protected修饰时，子类的方法必须要大于等于protected，可以用public
 * 4、父类中的方法若使用private. static. final任意修饰符修饰，那么，不能被子类重写。
 * 为什么要重写方法?或者方法重写的目的是什么?
 * 若子类从父类中维承过来的方法，不能满足子类特有的需求时，子类就需要重写父类中相应的方法，方法的重写
 * 也是程序扩展的体现。
 *
 *
 * 面试题：overloading和overriding的区别
 * overloading:方法的重载，发生在同一个类中，方法名相同，参数列表不同，返回值无关。
 * overriding :方法的重写，发生在子父类中，方法名相同，参数列表相同，返回值相同，
 *              子类的访问修饰符要大于或等于父类的访问修饰符，子类的异常声明必须小于或等于父类的异常声明
 *              如果方法被private. static. final任意修饰符修饰，那不能被重写
 **/
public class Test1 {
    public static void main(String[] args) throws Exception {
        HomeDog homeDog = new HomeDog("小明");
        homeDog.print();
        homeDog.eat();
        HuskyDog hd = new HuskyDog("小红");
        hd.eat();
    }
}

class Dog {
    protected String name;
    protected String sex;
    private int age;//private类型不能被继承
    public Dog(String name,String sex){
        this.name = name;
        this.sex = sex;
        System.out.println("我是Dog的构造方法");
    }
    public void eat() throws Exception{
        System.out.println("吃饭");
    }
}

class HomeDog extends Dog {
    //Dog父类没有无参的构造方法，因此要用super来调用带参数的父类构造方法，父类有几个参数，super中就要写几个参数
    public HomeDog(String name){
        super(name,"公");
        System.out.println("我是HomeDog的构造方法");
    }
    public void print() {
        //super.属性 表示调用父类的属性，如果是继承过来的属性，那么super可以省略
        System.out.println(super.name + "是一只家狗，汪汪！");
    }
    //重写父类eat的方法
    public void eat() throws Exception{
        super.eat();//调用父类的方法
        System.out.println("我是家狗，我喜欢吃骨头！");
    }
}

class HuskyDog extends HomeDog {
    //HomeDog父类没有无参的构造方法，因此要用super来调用带参数的父类构造方法，父类有几个参数，super中就要写几个参数
    public HuskyDog(String name) {
        super(name);
    }

    public void show() {
        System.out.println("我是husky，我能跳舞");
    }
    //重写父类eat的方法
    public void eat(){
        System.out.println("我是husky，我喜欢吃鸡肝！");
    }
}
